package net.yeah.mickey_zhouyou.util.fcs.elem;

import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.script.ScriptContext;

import net.yeah.mickey_zhouyou.util.ClassFieldsCache;
import net.yeah.mickey_zhouyou.util.fcs.ReaderOverException;
import net.yeah.mickey_zhouyou.util.fcs.ReaderWrapper;
import net.yeah.mickey_zhouyou.util.fcs.serialize.IConvertor;

public class Obj {
	protected String name;
	protected List<Selector> selectorList = new ArrayList<Selector>(0);

	public static Obj create(ReaderWrapper reader) throws IOException {
		String str;
		try {
			str = reader.readAString();
		} catch (ReaderOverException e) {
			str = null;
		}
		if (str == null)
			return null;
		if (isConstants(str))
			return new ObjConstants(str.substring(1, str.length() - 1));
		Obj res = new Obj();
		res.name = str;
		Selector selector = null;
		while ((selector = lookupSelector(reader)) != null)
			res.selectorList.add(selector);
		return res;
	}

	private static Selector lookupSelector(ReaderWrapper reader)
			throws IOException {
		char c;
		try {
			c = reader.lookNotBlank();
		} catch (ReaderOverException e) {
			return null;
		}
		if (c == '.')
			return FieldSelector.create(reader);
		if (c == '(')
			return ConditionSelector.create(reader);
		if (c == '[')
			return IdxSelector.create(reader);
		return null;
	}

	private static boolean isConstants(String str) {
		return str != null && str.length() >= 2 && str.charAt(0) == '\''
				&& str.charAt(str.length() - 1) == '\'';
	}

	public LeftValue asLeftValue(IConvertor objConvertor,
			ScriptContext context, Object upperObj) {
		if (this.selectorList == null || this.selectorList.size() == 0) {
			if (upperObj != null)
				return new LeftValue(null, upperObj, null);
			else
				return new LeftValue(this.name,
						context.getAttribute(this.name), null);
		}
		Selector lastSelector = this.selectorList
				.get(this.selectorList.size() - 1);
		if (lastSelector instanceof FieldSelector) {
			Object res = null;
			if (upperObj != null)
				res = upperObj;
			else
				res = context.getAttribute(this.name);
			for (int idx = 0; idx < this.selectorList.size() - 1; ++idx) {
				Selector selector = this.selectorList.get(idx);
				res = selector.select(res, objConvertor, context);
				if (res == null)
					break;
			}
			LeftValue lv = null;
			if (res != null)
				lv = new LeftValue(null, res, (FieldSelector) lastSelector);
			return lv;
		}
		throw new RuntimeException("做为左值的对象的最后一个选择器必须为属性选择器！");
	}

	public Object asRightValue(IConvertor objConvertor, Field field,
			ScriptContext context, Object upperObj) {
		if (upperObj == null
				&& (this.selectorList == null || this.selectorList.size() == 0))
			return context.getAttribute(this.name);
		Object res;
		if (upperObj == null)
			res = context.getAttribute(this.name);
		else
			res = upperObj;
		for (Selector selector : this.selectorList) {
			res = selector.select(res, objConvertor, context);
			if (res == null)
				break;
		}
		return res;
	}

	public static class LeftValue {
		private String name;
		private Object obj;
		private FieldSelector selector;

		public LeftValue(String name, Object obj, FieldSelector selector) {
			this.name = name;
			this.obj = obj;
			this.selector = selector;
		}

		public Object getObj() {
			return obj;
		}

		public FieldSelector getSelector() {
			return selector;
		}

		public Field getField() {
			if (obj != null && selector != null) {
				Object o = null;
				if (obj instanceof Iterable) {
					Iterable<?> i = (Iterable<?>) obj;
					Iterator<?> it = i.iterator();
					if (it.hasNext())
						o = it.next();
				} else if (obj.getClass().isArray()) {
					if (Array.getLength(obj) > 0)
						o = Array.get(obj, 0);
				}
				if (o != null)
					return ClassFieldsCache.getField(o.getClass(),
							selector.fieldName);
			}
			return null;
		}

		public void assignment(Object value, ScriptContext context) {
			if (selector != null)
				ClassFieldsCache.setValue(obj, selector.fieldName, value);
			else
				context.setAttribute(name, value, ScriptContext.ENGINE_SCOPE);
		}

		@SuppressWarnings("unchecked")
		public void add(Object value) {
			// if (value == null)
			// return;// 忽略空对象的添加
			Object fo = ClassFieldsCache.getValue(obj, selector.fieldName);
			Field field = ClassFieldsCache.getField(obj.getClass(),
					selector.fieldName);
			if (field == null)
				throw new RuntimeException("读取属性失败");
			if (fo == null) {
				if (Collection.class.equals(field.getType())
						|| List.class.equals(field.getType())) {
					fo = new ArrayList<Object>(1);
					((ArrayList<Object>) fo).add(value);
					ClassFieldsCache.setValue(obj, selector.fieldName, fo);
				} else if (Set.class.equals(field.getType())) {
					fo = new HashSet<Object>();
					((Set<Object>) fo).add(value);
					ClassFieldsCache.setValue(obj, selector.fieldName, fo);
				} else if (field.getType().isArray()) {
					fo = new Object[] { value };
					ClassFieldsCache.setValue(obj, selector.fieldName, fo);
				} else
					throw new RuntimeException("属性的类型不支持添加操作");
			} else {
				if (Collection.class.isAssignableFrom(field.getType())) {
					Collection<Object> coll = (Collection<Object>) fo;
					if (value != null && value.getClass().isArray()) {
						int len = Array.getLength(value);
						if (len > 0) {
							Object o = Array.get(value, 0);
							if (canBeEveryAdd(o, field)) {
								for (int i = 0; i < len; ++i)
									coll.add(Array.get(value, i));
							} else
								coll.add(value);
						}
					} else if (value != null && value instanceof List) {
						List<?> list = (List<?>) value;
						int len = list.size();
						if (len > 0) {
							Object o = list.get(0);
							if (canBeEveryAdd(o, field)) {
								for (Object o2 : list)
									coll.add(o2);
							} else
								coll.add(value);
						}
					} else
						coll.add(value);
				} else
					throw new RuntimeException("属性的类型不支持添加操作");
			}
		}

		private boolean canBeEveryAdd(Object o, Field field) {
			boolean ar = true;
			Type gt = field.getGenericType();
			if (gt instanceof ParameterizedType) {
				Type t = ((ParameterizedType) gt).getActualTypeArguments()[0];
				if (!(t instanceof TypeVariable)
						&& !(t instanceof GenericArrayType)
						&& !(t instanceof ParameterizedType)
						&& !(t instanceof WildcardType)) {
					if (!((Class<?>) t).isAssignableFrom(o.getClass()))
						ar = false;
				}
			}
			return ar;
		}
	}
}
